package iosr11.contact.dao;

import iosr11.data.Group;
import iosr11.data.User;

import java.net.URL;
import java.util.List;
import java.util.logging.Logger;

import com.google.gdata.client.contacts.ContactsService;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.contacts.ContactEntry;
import com.google.gdata.data.contacts.ContactFeed;
import com.google.gdata.data.contacts.ContactGroupEntry;
import com.google.gdata.data.contacts.ContactGroupFeed;
import com.google.gdata.data.contacts.GroupMembershipInfo;
import com.google.gdata.data.extensions.Email;

public class ContactsHelperImpl implements ContactsHelper {

	private ContactsService service;
	//private static ContactsImpl contactsImpl;
	private String username;

	private static String TITLE = "iosr_team11_contacts";
	private static String PAGE = "http://www.google.com/m8/feeds/";
	private static String TYPE_C = "contacts/";
	private static String TYPE_G = "groups/"; 
	private Logger log = Logger.getLogger("service-log");
	
	public ContactsHelperImpl(){
		service = new ContactsService(TITLE);
		username = "iosr.team11@gmail.com";
		this.autenticate(username, "iosr_team");
	}
	
	@Override
	public boolean addUser(User user) {
		if (user == null) return false;
		ContactEntry entry = new ContactEntry();
		entry.setTitle(new PlainTextConstruct(user.getName()));
		Email defaultMail = new Email();
		defaultMail.setAddress(user.getEmail());
		defaultMail.setRel("http://schemas.google.com/g/2005#home");
		defaultMail.setPrimary(true);
		entry.addEmailAddress(defaultMail);
		try {
			URL postURL = new URL(PAGE+TYPE_C+username+"/full");
			user.setId((service.insert(postURL, entry)).getId());
			return true;
		}
		catch (Exception e){
			e.printStackTrace();
			log.warning("Exception przy dodawaniu kontaktu: "+user.getName());
			return false;
		}
	}
	
	@Override
	public User getUser(String name) {
		if (!name.contains("@")) {	// szuka po nazwie
			try {
				URL feedURL = new URL(PAGE + TYPE_C + username + "/full");
				ContactFeed resultFeed = service.getFeed(feedURL,
						ContactFeed.class);
				for (ContactEntry entry : resultFeed.getEntries()) {
					if (entry.getTitle().getPlainText().equals(name))
						return this.rewrite(entry);
				}
				log.info("nie znaleziono kontaktu dla podanej nazwy: "+name);
				return null;
			} catch (Exception e) {
				e.printStackTrace();
				log.warning("Exception przy wyszukiwaniu kontaktu: "+name);
				return null;
			}
		}
		else { // szuka po e-mailu
			try{
				
				URL feedURL = new URL(PAGE + TYPE_C + username + "/full");
				ContactFeed resultFeed = service.getFeed(feedURL,
						ContactFeed.class);
				for (ContactEntry entry : resultFeed.getEntries()) {
					if (entry.getEmailAddresses() != null){
						for (Email email : entry.getEmailAddresses()){
							if (email.getAddress().equals(name))
								return this.rewrite(entry);
						}
					}
						
				}
				log.info("nie znaleziono kontaktu dla podanego email'a: "+name);
				return null;
			}
			catch (Exception e){
				e.printStackTrace();
				log.warning("Exception przy wyszukiwaniu kontaktu: "+name);
				return null;
			}
		}
	}
	
	@Override
	public User getUserByRef(String ref) {
		if (ref == null) return null;
		if (!ref.contains("http")) return null;
		try {
			URL url = new URL(ref);
			ContactEntry entry = service.getEntry(url, ContactEntry.class);
			return this.rewrite(entry);
		}
		catch (Exception e){
			e.printStackTrace();
			log.warning("Exception przy wyszukiwaniu kontaktu dla ref: "+ref);
			return null;
		}
	}

	private void changeForUpdate(ContactEntry rezult, ContactEntry data){
		rezult.setTitle(data.getTitle());
		rezult.getEmailAddresses().clear();
		rezult.getEmailAddresses().addAll(data.getEmailAddresses());
		rezult.getGroupMembershipInfos().clear();
		//rezult.getGroupMembershipInfos().addAll(data.getGroupMembershipInfos());	
	}
	
	@Override
	public boolean updateUser(User user) {
		ContactEntry entry = this.rewrite(user);
		try {
			URL url = new URL(user.getId());
			ContactEntry old_entry = service.getEntry(url, ContactEntry.class);
			this.changeForUpdate(old_entry, entry);
			old_entry.update();
			/*
			service.update(new URL(old_entry.getEditLink().getHref()), entry);*/
			return true;
		}
		catch (Exception e){
			e.printStackTrace();
			log.warning("blad w zmianie danych uzytkownika");
			return false;
		}
	}
	
	@Override
	public boolean deleteUser(String id) {
		try {
			URL url = new URL(id);
			ContactEntry entryToDelete = service.getEntry(url, ContactEntry.class);
			return this.deleteUser(entryToDelete);
		}
		catch (Exception e){
			return false;
		}
	}
	
	@Override
	public boolean deleteUser(ContactEntry user) {
		try {
			String tmp = user.getTitle().getPlainText();
			user.delete();
			log.info("isinieto kontakt: "+tmp);
			return true;
		}
		catch (Exception e) {
			e.printStackTrace();
			log.warning("Blad przy usuwaniu kontaktu");
			return false;
		}
	}

	@Override
	public User rewrite(ContactEntry entry) {
		if (entry == null) return null;
		User user = new User();
		user.setId(entry.getId());
		user.setName(entry.getTitle().getPlainText());
		user.setEmail(entry.getEmailAddresses().get(0).getAddress());
		
		// pobranie danych o grupach i ewentualnie samych grup
		if (entry.getGroupMembershipInfos() != null){
			log.info("przepisywanie grup z formatu google w ilosci: "+entry.getGroupMembershipInfos().size());
			for(GroupMembershipInfo info : entry.getGroupMembershipInfos()){
				Group grp = this.getGroupByRef(info.getHref());
				user.addGroup(grp);
			}
		}
		return user;
	}
	
	@Override
	public ContactEntry rewrite(User user) {
		ContactEntry entry = new ContactEntry();
		entry.setId(user.getId());
		entry.setTitle(new PlainTextConstruct(user.getName()));
		Email defaultMail = new Email();
		defaultMail.setAddress(user.getEmail());
		defaultMail.setRel("http://schemas.google.com/g/2005#home");
		defaultMail.setPrimary(true);
		entry.addEmailAddress(defaultMail);
		
		// przepisanie grup
		entry.getGroupMembershipInfos().clear();
		if (user.getGroups()!=null){
			log.info("przepisywanie grup w ilosci: "+user.getGroups().size());
			for (Group grp : user.getGroups()){
				GroupMembershipInfo info = new GroupMembershipInfo();
				info.setHref(grp.getId());
				entry.getGroupMembershipInfos().add(info);
			}
		}
		
		return entry;
	}
	
	/*
	 * Funkcje do obslugi grup kontaktow - uzywane wylacznie do studentow
	 */
	
	@Override
	public Group rewrite(ContactGroupEntry entry) {
		Group group = new Group();
		group.setId(entry.getId());
		group.setTitle(entry.getTitle().getPlainText());
		return group;
	}

	@Override
	public ContactGroupEntry rewrite(Group group) {
		ContactGroupEntry entry = new ContactGroupEntry();
		entry.setTitle(new PlainTextConstruct(group.getTitle()));
		return entry;
	}

	@Override
	public boolean addGroup(Group group) {
		ContactGroupEntry entry = this.rewrite(group);
		try {
			URL postURL = new URL(PAGE+TYPE_G+username+"/full");
			group.setId((service.insert(postURL, entry)).getId());
			log.info("dodano grupe: "+group.getTitle());
			return true;
		}
		catch (Exception e){
			e.printStackTrace();
			log.warning("Exception przy dodawaniu grupy: "+group.getTitle());
			return false;
		}
	}

	@Override
	public Group getGroupByRef(String ref) {
		if (ref == null){
			log.warning("zla referencja -null");
			return null;
		}
		
		if (!ref.contains("http")) {
			log.warning("zla referencja -nie url");
			return null;
		}
		try {
			URL url = new URL(ref);
			ContactGroupEntry entry = service.getEntry(url, ContactGroupEntry.class);
			log.info("Pobrano nowa grupe: "+entry.getTitle().getPlainText());
			return this.rewrite(entry);
		}
		catch (Exception e){
			e.printStackTrace();
			log.warning("Exception przy wyszukiwaniu grupy dla ref: "+ref);
			return null;
		}
	}

	@Override
	public boolean addUserToGroup(User user, Group group) {
		ContactEntry entry = this.rewrite(user);
		GroupMembershipInfo info = new GroupMembershipInfo();
		info.setHref(group.getId());
		entry.getGroupMembershipInfos().add(info);
		
		try {
			URL url = new URL(user.getId());
			ContactEntry old_entry = service.getEntry(url, ContactEntry.class);
			service.update(new URL(old_entry.getEditLink().getHref()), entry);
			log.info("dodano informacje o nowej grupie");
			return true;
		}
		catch (Exception e){
			e.printStackTrace();
			log.warning("blad w zmianie danych uzytkownika");
			return false;
		}
	}
	
	@Override
	public Group getGroup(String title) {
		ContactGroupEntry entry = this.findContactGroup(title);
		return this.rewrite(entry);
	}

	private ContactGroupEntry findContactGroup(String title){
		try {
			URL feedUrl = new URL(PAGE+TYPE_G+username+"/full");
			ContactGroupFeed resultFeed = service.getFeed(feedUrl, ContactGroupFeed.class);
			
			if (resultFeed == null){
				log.info("brak grup w systemie - null");
				return null;
			}
			
			for (ContactGroupEntry tmp : resultFeed.getEntries()){
				if (tmp.getTitle().getPlainText().equals(title)){
					log.info("znaleziono grupe");
					return tmp;
				}
			}
			log.info("nie znaleziono grupy o podanej nazwie: "+title);
			return null;
		}
		catch (Exception e){
			e.printStackTrace();
			log.warning("nie znaleziono grupy o podanej nazwie: "+title+" -wystapil wyjatek");
			return null;
		}
	}

	@Override
	public boolean deleteGroup(Group group) {
		ContactGroupEntry entry = this.findContactGroup(group.getTitle());
		try {
			entry.delete();
			return true;
		}
		catch (Exception e){
			e.printStackTrace();
			log.warning("nie powiodlo sie usuniece grupy: "+group.getTitle());
			return false;
		}
	}

	@Override
	public List<Group> getUserGroups(User user) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean updateGroup(Group group) {
		// TODO Auto-generated method stub
		return false;
	}











	


	/*
	 * zbedne funkcje - do usuniecia w przyszlosci 
	 */


	@Override
	public ContactsService getService() {
		return service;
	}

	@Override
	public void setService(ContactsService service, String username) {
		this.service = service;
		this.username = username;
	}

	@Override
	public boolean autenticate(String username, String password){
		try{
			service.setUserCredentials(username, password);
			this.username=username;
		}
		catch (Exception e){
			e.printStackTrace();
			return false;
		}
		return true;
	}
	
	@Override
	public String addNewUserReturnId(ContactEntry user) {
		try {
			URL postURL = new URL(PAGE+TYPE_C+username+"/full");
			ContactEntry afterAdd = service.insert(postURL, user);
			return afterAdd.getId();
		}
		catch (Exception e){
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public String addNewUserReturnId(String realUserName, String email) {
		ContactEntry entry = new ContactEntry();
		entry.setTitle(new PlainTextConstruct(realUserName));
		Email defaultMail = new Email();
		defaultMail.setAddress(email);
		defaultMail.setRel("http://schemas.google.com/g/2005#home");
		defaultMail.setPrimary(true);
		entry.addEmailAddress(defaultMail);
		return this.addNewUserReturnId(entry);
	}
	
	@Override
	public boolean addNewUser(ContactEntry user){
		if (addNewUserReturnId(user)!=null)
			return true;
		else
			return false;
	}

	@Override
	public boolean addNewUser(String realUserName, String email) {
		if (this.addNewUserReturnId(realUserName, email) != null)
			return true;
		else
			return false;
	}

	@Override
	public ContactEntry getUserOld(String name) {
		if (!name.contains("@")) {	// szuka po nazwie
			try {
				URL feedURL = new URL(PAGE + TYPE_C + username + "/full");
				ContactFeed resultFeed = service.getFeed(feedURL,
						ContactFeed.class);
				for (ContactEntry entry : resultFeed.getEntries()) {
					if (entry.getTitle().getPlainText().equals(name))
						return entry;
				}
				return null;
			} catch (Exception e) {
				e.printStackTrace();
				return null;
			}
		}
		else { // szuka po e-mailu
			try{
				
				URL feedURL = new URL(PAGE + TYPE_C + username + "/full");
				ContactFeed resultFeed = service.getFeed(feedURL,
						ContactFeed.class);
				for (ContactEntry entry : resultFeed.getEntries()) {
					if (entry.getEmailAddresses() != null){
						for (Email email : entry.getEmailAddresses()){
							if (email.getAddress().equals(name))
								return entry;
						}
					}
						
				}
				return null;
			}
			catch (Exception e){
				e.printStackTrace();
				return null;
			}
		}
	}

	@Override
	public boolean addUserGroup(ContactEntry contact, ContactGroupEntry group) {
		GroupMembershipInfo info = new GroupMembershipInfo();
		info.setHref(group.getId());
		contact.addGroupMembershipInfo(info);
		return true;
	}

	@Override
	public boolean addUserGroup(ContactEntry contact, String groupName) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public ContactEntry getUser(URL url) {
		try {
			return service.getEntry(url, ContactEntry.class);
		}
		catch (Exception e){
			e.printStackTrace();
			return null;
		}
	}

}
